package cn.itsource.pethome.user.service.impl;

import cn.itsource.pethome.basic.constant.PetHomeConstant;
import cn.itsource.pethome.basic.util.HttpClientUtils;
import cn.itsource.pethome.basic.util.MD5Utils;
import cn.itsource.pethome.basic.util.StrUtils;
import cn.itsource.pethome.user.domain.LoginInfo;
import cn.itsource.pethome.user.domain.User;
import cn.itsource.pethome.user.domain.WechatUser;
import cn.itsource.pethome.user.domain.dto.UserDto;
import cn.itsource.pethome.user.mapper.LoginInfoMapper;
import cn.itsource.pethome.user.mapper.UserMapper;
import cn.itsource.pethome.user.mapper.WechatMapper;
import cn.itsource.pethome.user.service.IWechatService;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class WechatServiceImpl implements IWechatService {
    @Autowired
    private LoginInfoMapper loginInfoMapper;
    @Autowired
    private UserMapper userMapper;


    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private WechatMapper wechatMapper;


    @Override
    public Map<String, Object> handleCallBack(String code) {
        //获取tokenurl地址
        String tokenUrl = PetHomeConstant.TOKENURL.replace("APPID", PetHomeConstant.APPID)
                .replace("SECRET", PetHomeConstant.SECRET)
                .replace("CODE", code);
        //通过java程序发送get请求，它就会返回json格式数据
        String tokenJosnStr = HttpClientUtils.httpGet(tokenUrl);

        //将josn字符串转为json对象
        JSONObject jsonObject = JSONObject.parseObject(tokenJosnStr);

        //获取微信唯一标识
        String openid = jsonObject.getString("openid");

        //获取token值
        String access_token  = jsonObject.getString("access_token");

        //获取unionid（也相当于用户唯一标识，实际没什么作用）
        String unionid = (String)jsonObject.get("unionid");

        //获取userinfoUrl地址-》可获取资源
        String userInfoUrl = PetHomeConstant.USERINFOURL.replace("ACCESS_TOKEN", access_token )
                .replace("OPENID", openid);

        //通过java程序发送请求 以及 token  和 openid  查出微信用户基本信息json字符串
        String userInfoJson = HttpClientUtils.httpGet(userInfoUrl);

        //将json字符串转为json对象
        jsonObject = JSONObject.parseObject(userInfoJson);

        //通过微信用户唯一标识openid在微信用户表中查看是否有对应的数据
        WechatUser wechatUser = wechatMapper.loadByOpenid(openid);

        //创建一个map集合，封装数据，传递到前端，前端拿到后端传递的数据，可以做判断
        Map<String, Object> map = new HashMap<>();
        //判断是否存在微信用户信息
        //如果为空证明当前用户还未做微信绑定
        if(wechatUser == null){
            //创建一个微信用户对象
            WechatUser user = new WechatUser();
            //给微信用户赋值openid
            user.setOpenid(openid);
            //赋值昵称
            user.setNickname(jsonObject.getString("nickname"));
            //赋值性别
            user.setSex(jsonObject.getBoolean("sex"));
            //头像
            user.setHeadimgurl(jsonObject.getString("headimgurl"));
            //授权之后唯一标志
            user.setUnionid(unionid);
            //赋值地址  国家 省份
            user.setAddress(jsonObject.getString("province")+" "+jsonObject.getString("city"));
            //把user对象给保存起来
            wechatMapper.save(user);
            //返回微信唯一标识到前端 前端跳转到绑定界面（绑定即将用户登录信息存储到微信用户表中）
            map.put("openid", openid);
            return map;
        }else {
            //如果有wechar对象 则从中取登录信息
            LoginInfo loginInfo = wechatUser.getLoginInfo();
            //如果没有登录信息
            if(loginInfo == null){
                //返回微信唯一标识到前端  前端处理  跳转到绑定界面（添加对应登录信息）
                map.put("openid", openid);
                return map;
            }else{
                //如果有 则直接登录 创建类似session机制 返回到前端你直接跳转到用户首页 并将token存到数据库
                //随机创建token
                String token = UUID.randomUUID().toString();
                //直接登录
                redisTemplate.opsForValue().set(token, loginInfo,30, TimeUnit.MINUTES);
                map.put("token", token);
                map.put("loginUser", loginInfo);
                return map;
            }
        }


    }

    @Override
    public Map<String, Object> binder(UserDto userDto) {
        //校验数据
        checkUserDto(userDto);
        //设置username，因为sal只写了username
        userDto.setUsername(userDto.getPhone());
        //判断手机号码是否在登录信息中已存在
        LoginInfo loginInfo = loginInfoMapper.loadByUserDto(userDto);
        //创建map集合，封装登录信息和token信息
        Map<String, Object> map = new HashMap<>();
        if(loginInfo == null){
            //临时对象转为LoginInfo
            loginInfo = userDto2LoginInfo(userDto);
            //保存LoginInfo
            loginInfoMapper.save(loginInfo);
            //loginInfo2User
            User user = loginInfo2User(loginInfo);
            //保存user对象
            userMapper.save(user);
        }
        //如果登录信息中有数据  或者保存过后执行
        //微信和用户绑定一起（修改t_wxuser表）
        wechatMapper.binder(loginInfo.getId(), userDto.getOpenid());
        //直接登录
        String token = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set(token, loginInfo, 30, TimeUnit.MINUTES);
        map.put("token", token);
        map.put("loginUser", loginInfo);
        return map;

    }

    private User loginInfo2User(LoginInfo loginInfo) {
        //创建用户对象
        User user = new User();
        //复制相同属性
        BeanUtils.copyProperties(loginInfo, user);
        //设置状态
        user.setState(PetHomeConstant.OK);
        //设置登录信息
        user.setLoginInfo(loginInfo);
        return user;
    }

    private LoginInfo userDto2LoginInfo(UserDto userDto) {
        //创建一个登录信息对象
        LoginInfo loginInfo = new LoginInfo();
        //设置电话
        loginInfo.setPhone(userDto.getPhone());
        //设置用户名
        loginInfo.setUsername(userDto.getPhone());
        //设置用户类型
        loginInfo.setType(userDto.getType());
        //设置用户初始密码盐值
        loginInfo.setSalt(StrUtils.getComplexRandomString(10));
        //设置用户初始密码 为电话号码
        loginInfo.setPassword(MD5Utils.encrypByMd5(loginInfo.getPhone()+loginInfo.getSalt()));
        //返回登录信息
        return loginInfo;
    }

    private void checkUserDto(UserDto userDto) {
        System.out.println(userDto.getPhone());
        System.out.println(userDto.getCode());
        System.out.println(userDto.getType());

        if(StringUtils.isEmpty(userDto.getPhone())||StringUtils.isEmpty(userDto.getCode())
                ||userDto.getType()==null){
            throw new RuntimeException("请输入完整信息!!");
        }
        //判断验证码是否过期
        String codeValue = (String) redisTemplate.opsForValue().get(PetHomeConstant.BINDER_VERIFICATION_CODE + ":" + userDto.getPhone());
        if(StringUtils.isEmpty(codeValue)){
            throw new RuntimeException("验证码已过期");
        }
        //判断验证码是否正确
        if(!codeValue.split(":")[0].toLowerCase().equals(userDto.getCode().toLowerCase())){
            throw new RuntimeException("验证码错误!!");
        }
    }
}
